package com.radar.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.FileUtil;
import com.radar.common.CinradType;
import com.radar.common.DateConstants;
import com.radar.common.ProductType;
import com.radar.io.CinradRadar;
import com.radar.model.ResultBody;
import com.radar.visualize.VCSMap;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.meteoinfo.global.PointD;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Api(tags = "2.0 雷达接口")
@RestController
@RequestMapping("zz")
@Slf4j
public class RadarZZController {

    private String processPath;

    @Value("${radar.process-zz-path:''}")

    public void setProcessPath(String processPath) {
        this.processPath = processPath;
    }

    @ApiOperation("2.2.单点雷达数据")
    @GetMapping("/point")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "obsTime", value = "obsTime", defaultValue = "2021-03-04 23:59:00", example = "2021-03-04 23:59:00", paramType = "query", required = true, dataType = "String"),
            @ApiImplicitParam(name = "index", value = "ref、vel的 index", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int"),
            @ApiImplicitParam(name = "lon", value = "lon", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int"),
            @ApiImplicitParam(name = "lat", value = "lat", defaultValue = "0", example = "0", paramType = "query", required = true, dataType = "int")
    })
    public ResultBody point(@ApiIgnore @RequestParam String obsTime, @RequestParam int index, @RequestParam double lon, @RequestParam double lat) {
        CinradRadar cinradRadar = null;
        try {
            if (StringUtils.isBlank(obsTime)) {
                return ResultBody.failed();
            }
            Date parse = DateUtil.parse(obsTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
            String realPath = this.processPath + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator;
            List<File> files = FileUtil.loopFiles(realPath, new RegexFileFilter("^(\\d{14})0.05V$"));
            if (files == null || files.size() != 1) {
                return ResultBody.failed();
            }
            cinradRadar = new CinradRadar();
            cinradRadar.parse(files.get(0).getAbsolutePath(), CinradType.RADAR_721);
            double ref = cinradRadar.radar.point(lon, lat, ProductType.REF, index);
            double vel = cinradRadar.radar.point(lon, lat, ProductType.VEL, index);
            double sw = cinradRadar.radar.point(lon, lat, ProductType.SW, index);
            cinradRadar.radar.close();
            return ResultBody.ok().put("ref", ref).put("vel", vel).put("sw", sw);
        } catch (Exception e) {
            log.error(ExceptionUtil.getSimpleMessage(e));
        }
        return ResultBody.failed();
    }

    @ApiOperation("2.3.剖面")
    @GetMapping("/vcs")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "obsTime", value = "obsTime", defaultValue = "/Users/xx/data/micaps/SINGLERADAR/ARCHIVES/PRE_QC/Z9836/Z_RADR_I_Z9836_20190730022600_O_DOR_CA_CAP.bin.bz2", example = "/Users/xx/data/micaps/SINGLERADAR/ARCHIVES/PRE_QC/Z9836/Z_RADR_I_Z9836_20190730022600_O_DOR_CA_CAP.bin.bz2", paramType = "query", required = true, dataType = "String"),
            @ApiImplicitParam(name = "type", value = "产品类别(REF,VEL,CR,ET,VIL)", defaultValue = "REF", example = "REF", paramType = "query", required = true, dataType = "String"),
            @ApiImplicitParam(name = "points", value = "点集合", defaultValue = "points", example = "110-27,111-27", paramType = "query", required = true, dataType = "String")
    })
    public ResultBody vcs(@ApiIgnore @RequestParam String obsTime, @RequestParam String points, @RequestParam String type){
        CinradRadar cinradRadar = null;
        try {
            if (StringUtils.isBlank(obsTime)) {
                return ResultBody.failed();
            }
            Date parse = DateUtil.parse(obsTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
            String realPath = this.processPath + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(parse, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator;
            List<File> files = FileUtil.loopFiles(realPath, new RegexFileFilter("^(\\d{14})0.05V$"));
            if (files == null || files.size() != 1) {
                return ResultBody.failed();
            }
            cinradRadar = new CinradRadar();
            cinradRadar.parse(files.get(0).getAbsolutePath(),CinradType.RADAR_721);
            List<PointD> list = new ArrayList<>();
            Arrays.asList(points.split(";")).forEach(i -> {
                list.add(new PointD(Double.parseDouble(i.split(":")[0]),Double.parseDouble(i.split(":")[1])));
            });
            VCSMap vcsMap = new VCSMap(cinradRadar.radar);
            VCSMap.VCSInfo vcsInfo = vcsMap.buildRasterInfo(ProductType.valueOf(type))
                    .altNum(100)
                    .pointNum(500)
                    .maxAlt(22);
            BufferedImage bufferedImage = vcsMap.simpleVCS(vcsInfo, list);
            cinradRadar.radar.close();
            return ResultBody.ok().data(imageToBase64(bufferedImage));
        } catch (Exception e) {
            log.error(ExceptionUtil.getSimpleMessage(e));
            if (cinradRadar.radar != null) {
                cinradRadar.radar.close();
            }
        }
        return ResultBody.failed();
    }

    @ApiOperation(value = "时间轴", httpMethod = "GET", notes = "listTimeLine")
    @GetMapping("/listTimeLine")
    public ResultBody listTimeLine(String yyyyMMdd) {
        try {
            if (!yyyyMMdd.isEmpty()) {
                // 时间参数格式判断
                DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd");
                fmt.parseLocalDateTime(yyyyMMdd).toDate();
            }
        } catch (Exception e) {
            return ResultBody.failed().msg("日期格式错误");
        }
        return ResultBody.ok().data(getTimeLine(yyyyMMdd));
    }

    public HashMap<String, Object> getTimeLine(String yyyyMMdd) {
        try {
            File dir;
            if (yyyyMMdd == null || yyyyMMdd.isEmpty()) {
                dir = Arrays.stream(FileUtil.ls(processPath))
                        .filter(i -> i.getName().length() == 8).min(Comparator.comparing(i -> -Long.parseLong(i.getName()))).orElse(null);
            } else {
                dir = new File(processPath + File.separator + DateUtil.format(DateUtil.parse(yyyyMMdd, "yyyy-MM-dd"), "yyyyMMdd"));
            }
            if (dir == null) {
                return null;
            }
            List<DateTime> collect = Arrays.stream(FileUtil.ls(dir.getAbsolutePath()))
                    .filter(i -> i.getName().length() == 12).map(file -> DateUtil.parse(file.getName().substring(0, 12), DateConstants.DATE_FORMAT_YYYYMMDD + "HHmm")).sorted().collect(Collectors.toList());
            List<Map<String, String>> list = new ArrayList<>();
            int index = 0;
            for (Date date : collect) {
                Map map = new HashMap();
                map.put("timestamp", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
                map.put("timeColor", "rgba(55,54,55,1)");
                map.put("showDay", false);
                map.put("showHour", false);
                int minute = DateUtil.minute(date);
                if (index % 5 == 0) {
                    map.put("timeStyleHeight", "15px");
                    map.put("showDay", true);
                    map.put("showHour", true);
                } else {
                    map.put("timeStyleHeight", "5px");
                }
                index ++;
                map.put("disabled", false);
                // 判断下 nc 文件是否存在
                if (FileUtil.exist(dir.getAbsolutePath() + File.separator + DateUtil.format(date, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator + "surface.dat.zip")){
                    list.add(map);
                }
            }
            HashMap timeLineMap = new HashMap();
            timeLineMap.put("initializationPosition", list.size() - 1);
            timeLineMap.put("data", list);
            return timeLineMap;
        } catch (Exception e) {
            return null;
        }
    }

    public String imageToBase64(BufferedImage br) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
        ImageIO.write(br, "png", baos);//写入流中
        byte[] bytes = baos.toByteArray();//转换成字节
        BASE64Encoder encoder = new BASE64Encoder();
        String pngBase64 = encoder.encodeBuffer(bytes).trim();//转换成base64串
        pngBase64 = pngBase64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
        return pngBase64;
    }
}
